#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

/* ============================================================= */
/* USER DEFINED PARAMETERS HERE                                  */
/* ============================================================= */
/* trun on/off debug func, off may save code size */
#define RING_BUFFER_DEBUG       1
/* ring buffer data type */
#define ring_buffer_data_t      uint8_t
/* ring buffer array size */
/* buffer can only (hold RING_BUFFER_SIZE - 1) by design */
#define RING_BUFFER_SIZE        128
/* ring buffer index, enough to hold RING_BUFFER_SIZE */
#define ring_buffer_size_t      uint8_t

/* ============================================================= */
/* RING BUFFER STRUCT HERE                                       */
/* ============================================================= */
typedef enum _ring_buffer_err {
    RING_BUFFER_OK = 0,
    RING_BUFFER_EMPTY = -1,
    RING_BUFFER_NOENOUGH = -2,
    RING_BUFFER_OVERFLOW = -3,
    RING_BUFFER_PTR_NULL = -4,
} ring_buffer_err;

typedef struct _ring_buffer_t {
    ring_buffer_data_t buffer[RING_BUFFER_SIZE];
    ring_buffer_size_t head;
    ring_buffer_size_t tail;
} ring_buffer_t;

/* ============================================================= */
/* RING BUFFER INTERFACE HERE                                    */
/* ============================================================= */

/**
 * @description: init ring buffer struct
 * @param {ring_buffer_t} *ring_buffer
 * @return {*}
 */
void ring_buffer_init(ring_buffer_t *ring_buffer);

/**
 * @description: enqueue a data into ring buffer
 * @param {ring_buffer_t} *ring_buffer
 * @param {ring_buffer_data_t} data
 * @return {*}: (int)1 for success, negative for error
 */
int ring_buffer_enqueue(ring_buffer_t *ring_buffer, ring_buffer_data_t data);

/**
 * @description: enqueue data array into ring buffer
 * @param {ring_buffer_t} *ring_buffer
 * @param {constring_buffer_data_t} *arr
 * @param {ring_buffer_size_t} len
 * @return {*}: number of data stored, negative for error
 */
int ring_buffer_enqueue_arr(ring_buffer_t *ring_buffer, const ring_buffer_data_t *arr, ring_buffer_size_t len);

/**
 * @description: dequeue a data from ring buffer
 * @param {ring_buffer_t} *ring_buffer
 * @param {ring_buffer_data_t} *data
 * @return {*}: (int)1 for success, negative for error
 */
int ring_buffer_dequeue(ring_buffer_t *ring_buffer, ring_buffer_data_t *data);

/**
 * @description: dequeue data array from ring buffer
 * @param {ring_buffer_t} *ring_buffer
 * @param {ring_buffer_data_t} *data
 * @param {ring_buffer_size_t} len
 * @return {*}: number of data getted, negative for error
 */
int ring_buffer_dequeue_arr(ring_buffer_t *ring_buffer, ring_buffer_data_t *data, ring_buffer_size_t len);

/* ============================================================= */
/* RING BUFFER DEBUG HERE                                        */
/* ============================================================= */
#if RING_BUFFER_DEBUG
#define ring_buffer_print       printf
#define RING_BUFFER_FORMAT      "0x%x"
void ring_buffer_debug(ring_buffer_t *ring_buffer);
#endif

#endif /* __RING_BUFFER_H__ */

